package com.jidong.test_springboot.config;

import java.time.Duration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheManager.RedisCacheManagerBuilder;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping;

/***
 * 配置springcache和redis整合的时候，用redisTemplate和CacheManager
 * 
 * 我们不写这个也行，因为我们的那个整合包会自动帮我们创建，
 * 但是他创建的redisTemplate用的序列化规则是jdk默认的，导致存入redis的数据，我们看不出来。
 如果我们想让redis存的数据我们能认出来，我们就自己写RedisTemplate 指定我们自己的序列化规则就行了
 
 一旦我们自己创建了RedisTemplate，我们那个整合包就自动用我们自己的，就不在用他帮我们生成的那个了
 *
 */
@Configuration  //把这个注解注释掉 也没影响，只是序列化规则不一样而已
public class RedisConfig {
	/**
	 * RedisTemplate配置
	 */
	@Bean
	public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
		// 设置序列化
		Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
		ObjectMapper om = new ObjectMapper();
		om.setVisibility(PropertyAccessor.ALL, Visibility.ANY);
		om.enableDefaultTyping(DefaultTyping.NON_FINAL);
		jackson2JsonRedisSerializer.setObjectMapper(om);
		// 配置redisTemplate
		
		RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
		
		redisTemplate.setConnectionFactory(lettuceConnectionFactory);
		
		RedisSerializer<?> stringSerializer = new StringRedisSerializer();
		
		redisTemplate.setKeySerializer(stringSerializer);// key序列化
		redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);// value序列化
		
		redisTemplate.setHashKeySerializer(stringSerializer);// Hash key序列化
		redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);// Hash value序列化
		redisTemplate.afterPropertiesSet();
		return redisTemplate;
	}

	/**
	 * 缓存配置管理器
	 */
	@Bean
	public CacheManager cacheManager(LettuceConnectionFactory factory) {
		//先创建一个builder
		RedisCacheManagerBuilder builder=RedisCacheManager.builder(RedisCacheWriter.nonLockingRedisCacheWriter(factory));
		//在redis服务器创建工作空间，也就是存放数据的位置，没配置CacheManager的时候，会自动帮我们创建一个叫default的位置
		//也就是Cacheable注解里的value属性。凡是在value里用的名字，都得在这里配置过
		Set<String> cacheNames=new HashSet<String>();
		cacheNames.add("default");//原来默认的，我们现有系统，数据全放这里了
		cacheNames.add("shiro-cache");//凡是shiro的相关的数据都放到这个位置 本系统没用到
		cacheNames.add("dept-cache");//凡是部门相关的数据都放到这个位置 本系统没用到
		builder=builder.initialCacheNames(cacheNames);
		//为每个位置制作独立的配置信息
		
		RedisCacheConfiguration config=RedisCacheConfiguration.defaultCacheConfig()
				.entryTtl(Duration.ofMinutes(30L))//设置数据超时时间为30分钟
				.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))//设置key的序列化
				.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))//设置value序列化
				.disableCachingNullValues();//如果是空值则不缓存
				
		
		Map<String,RedisCacheConfiguration> cfgs=new HashMap<>();
		cfgs.put("default", config);
		cfgs.put("shiro-cache", config.entryTtl(Duration.ofMinutes(60L)));//设置shiro一小时过期
		cfgs.put("dept-cache", config.entryTtl(Duration.ofMinutes(120L)));//设置dept两小时过期
		builder=builder.withInitialCacheConfigurations(cfgs);
		//用builder创建了CacheManager
		RedisCacheManager cacheManager=builder.build();
		return cacheManager;
	}
}
